From 76e8d2ff6ad9e25ef46356efe22dc0a53446747c Mon Sep 17 00:00:00 2001 From: "mjw@wray-m-3.hpl.hp.com" Date: Thu, 1 Jul 2004 12:06:02 +0000 Subject: [PATCH] bitkeeper revision 1.1041.3.1 (40e3fe2a5JO0HpkIeSaP8q6IITbNAQ) Documentation and a couple of tidies. --- tools/python/xen/xend/server/SrvDomainDir.py | 20 +++- tools/python/xen/xend/server/blkif.py | 59 +++++++--- tools/python/xen/xend/server/channel.py | 12 +- tools/python/xen/xend/server/console.py | 24 +--- tools/python/xen/xend/server/controller.py | 87 +++++++++++++-- tools/python/xen/xend/server/domain.py | 21 ++++ tools/python/xen/xend/server/messages.py | 27 +++++ tools/python/xen/xend/server/netif.py | 111 ++++++++++++------- 8 files changed, 265 insertions(+), 96 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index af4bc7a15c..03c869051e 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -1,5 +1,6 @@ # Copyright (C) 2004 Mike Wray +import traceback from StringIO import StringIO from twisted.protocols import http @@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir): val = None try: dom = self.xd.domain_get(x) + if not dom: raise KeyError('No such domain') val = SrvDomain(dom) except KeyError, ex: print 'SrvDomainDir>', ex @@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir): return v def op_create(self, op, req): + """Create a domain. + Expects the domain config in request parameter 'config' in SXP format. + """ ok = 0 try: configstring = req.args.get('config')[0] @@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir): config = pin.get_val() ok = 1 except Exception, ex: - print 'op_create>', ex + print 'op_create> Exception in config', ex + traceback.print_exc() if not ok: req.setResponseCode(http.BAD_REQUEST, "Invalid configuration") return "Invalid configuration" @@ -60,10 +66,10 @@ class SrvDomainDir(SrvDir): deferred.addCallback(self._cb_op_create, configstring, req) return deferred except Exception, ex: - raise - #return ['err', str(ex) ] - #req.setResponseCode(http.BAD_REQUEST, "Error creating domain") - #return str(ex) + print 'op_create> Exception creating domain:' + traceback.print_exc() + req.setResponseCode(http.BAD_REQUEST, "Error creating domain") + return str(ex) #return error.ErrorPage(http.BAD_REQUEST, # "Error creating domain", # str(ex)) @@ -90,6 +96,8 @@ class SrvDomainDir(SrvDir): return val def op_restore(self, op, req): + """Restore a domain from file. + """ fn = FormFn(self.xd.domain_restore, [['file', 'str']]) val = fn(req.args) @@ -131,6 +139,8 @@ class SrvDomainDir(SrvDir): req.write('') def form(self, req): + """Generate the form(s) for domain dir operations. + """ req.write('
' % req.prePathURL()) req.write('') diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 4e2a49f7d8..7310494377 100755 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + from twisted.internet import defer from xen.xend import sxp @@ -28,6 +30,11 @@ class BlkifControllerFactory(controller.ControllerFactory): self.registerChannel() def createInstance(self, dom, recreate=0): + """Create a block device controller for a domain. + + dom domain + recreate if true it's a recreate (after xend restart) + """ d = self.addDeferred() blkif = self.getInstanceByDom(dom) if blkif: @@ -42,29 +49,50 @@ class BlkifControllerFactory(controller.ControllerFactory): return d def getDomainDevices(self, dom): + """Get the block devices for a domain. + + dom domain + + returns devices + """ blkif = self.getInstanceByDom(dom) return (blkif and blkif.getDevices()) or [] def getDomainDevice(self, dom, vdev): + """Get a block device from a domain. + + dom domain + vdev device index + + returns device + """ blkif = self.getInstanceByDom(dom) return (blkif and blkif.getDevice(vdev)) or None def setControlDomain(self, dom, recreate=0): + """Set the back-end block device controller domain. + + dom domain + recreate if true it's a recreate (after xend restart) + """ if self.dom == dom: return self.deregisterChannel() if not recreate: self.attached = 0 self.dom = dom self.registerChannel() - # - #if xend.blkif.be_port: - # xend.blkif.recovery = True - #xend.blkif.be_port = xend.main.port_from_dom(dom) def getControlDomain(self): + """Get the back-end block device controller domain. + """ return self.dom def reattachDevice(self, dom, vdev): + """Reattach a device (on changing control domain). + + dom domain + vdev device index + """ blkif = self.getInstanceByDom(dom) if blkif: blkif.reattachDevice(vdev) @@ -83,6 +111,9 @@ class BlkifControllerFactory(controller.ControllerFactory): return attached def reattached(self): + """Notify all block interface we have been reattached + (after changing control domain). + """ for blkif in self.getInstances(): blkif.reattached() @@ -147,7 +178,6 @@ class BlkDev(controller.Dev): return val def destroy(self): - print 'BlkDev>destroy>', self.vdev PrettyPrint.prettyprint(self.sxpr()) self.controller.send_be_vbd_destroy(self.vdev) @@ -157,7 +187,6 @@ class BlkifController(controller.Controller): """ def __init__(self, factory, dom): - #print 'BlkifController> dom=', dom controller.Controller.__init__(self, factory, dom) self.devices = {} @@ -172,7 +201,6 @@ class BlkifController(controller.Controller): self.attached = 1 self.evtchn = None self.registerChannel() - #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val = ['blkif', ['dom', self.dom]] @@ -183,8 +211,6 @@ class BlkifController(controller.Controller): return val def lostChannel(self): - print 'BlkifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() controller.Controller.lostChannel(self) def getDevices(self): @@ -201,8 +227,14 @@ class BlkifController(controller.Controller): def attachDevice(self, vdev, mode, segment, recreate=0): """Attach a device to the specified interface. + + vdev device index + mode read/write mode + segment segment + recreate if true it's being recreated (after xend restart) + + returns deferred """ - #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment dev = self.addDevice(vdev, mode, segment) if not dev: return -1 if recreate: @@ -214,13 +246,11 @@ class BlkifController(controller.Controller): return d def destroy(self): - print 'BlkifController>destroy> dom=', self.dom def cb_destroy(val): self.send_be_destroy() d = self.factory.addDeferred() d.addCallback(cb_destroy) self.send_be_disconnect() - #self.destroyDevices() def destroyDevices(self): for dev in self.getDevices(): @@ -276,11 +306,6 @@ class BlkifController(controller.Controller): self.factory.writeRequest(msg) pass - #def recv_fe_interface_status_changed(self, msg, req): - # (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg) - # print 'recv_fe_interface_status_changed>', hnd, status, chan - # pass - def send_fe_interface_status_changed(self): msg = packMsg('blkif_fe_interface_status_changed_t', { 'handle' : 0, diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py index da19d621c2..0c9d316dec 100755 --- a/tools/python/xen/xend/server/channel.py +++ b/tools/python/xen/xend/server/channel.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() from xen.lowlevel import xu from messages import msgTypeName @@ -24,14 +26,11 @@ class ChannelFactory: self.notifier = xu.notifier() def addChannel(self, channel): - """Add a channel. + """Add a channel. Registers with the notifier. """ idx = channel.idx self.channels[idx] = channel self.notifier.bind(idx) - # Try to wake it up - #self.notifier.unmask(idx) - #channel.notify() def getChannel(self, idx): """Get the channel with the given index (if any). @@ -40,6 +39,7 @@ class ChannelFactory: def delChannel(self, idx): """Remove the channel with the given index (if any). + Deregisters with the notifier. """ if idx in self.channels: del self.channels[idx] @@ -288,6 +288,8 @@ class Channel(BaseChannel): self.getRemotePort())) def handleNotification(self): + """Process outstanding messages in repsonse to notification on the port. + """ if self.closed: print 'handleNotification> Notification on closed channel', self return @@ -299,6 +301,8 @@ class Channel(BaseChannel): self.notify() def notify(self): + """Notify the other end of the port that messages have been processed. + """ if self.closed: return self.port.notify() diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py index 3227dc1b5e..336ccacca0 100755 --- a/tools/python/xen/xend/server/console.py +++ b/tools/python/xen/xend/server/console.py @@ -1,3 +1,4 @@ +# Copyright (C) 2004 Mike Wray from twisted.internet import reactor from twisted.internet import protocol @@ -12,11 +13,6 @@ import controller from messages import * from params import * -"""Telnet binary option.""" -TRANSMIT_BINARY = '0' -WILL = chr(251) -IAC = chr(255) - class ConsoleProtocol(protocol.Protocol): """Asynchronous handler for a console TCP socket. """ @@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol): self.loseConnection() return else: - # KAF: A nice quiet successful connect. Don't bother with telnet - # control sequence -- telnet is not the appropriate protocol here. + # KAF: A nice quiet successful connect. #self.transport.write("Connected to console %d on domain %d\n" # % (self.idx, self.controller.dom)) - #self.setTelnetTransmitBinary() eserver.inject('xend.console.connect', [self.idx, self.addr[0], self.addr[1]]) - def setTelnetTransmitBinary(self): - """Send the sequence to set the telnet TRANSMIT-BINARY option. - """ - self.write(IAC + WILL + TRANSMIT_BINARY) - def dataReceived(self, data): if self.controller.handleInput(self, data): self.loseConnection() @@ -105,7 +94,6 @@ class ConsoleController(controller.Controller): """ def __init__(self, factory, dom, console_port): - #print 'ConsoleController> dom=', dom, type(dom) controller.Controller.__init__(self, factory, dom) self.majorTypes = [ CMSG_CONSOLE ] self.status = "new" @@ -118,7 +106,6 @@ class ConsoleController(controller.Controller): self.registerChannel() self.listener = None self.listen() - #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val =['console', @@ -143,7 +130,6 @@ class ConsoleController(controller.Controller): def close(self): try: - #print 'ConsoleController> close dom=', self.dom self.status = "closed" if self.conn: self.conn.loseConnection() @@ -183,11 +169,11 @@ class ConsoleController(controller.Controller): self.listen() def requestReceived(self, msg, type, subtype): - #print '***Console', self.dom, msg.get_payload() self.rbuf.write(msg.get_payload()) self.handleOutput() def responseReceived(self, msg, type, subtype): + # Just ignore responses. pass def produceRequests(self): @@ -215,18 +201,14 @@ class ConsoleController(controller.Controller): Sends it to the connected console (if any). """ if self.closed(): - #print 'Console>handleOutput> closed' return -1 if not self.conn: - #print 'Console>handleOutput> not connected' return 0 while not self.rbuf.empty(): try: - #print 'Console>handleOutput> writing...' bytes = self.conn.write(self.rbuf.peek()) if bytes > 0: self.rbuf.discard(bytes) except socket.error, error: pass - #print 'Console>handleOutput<' return 0 diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py index 900c2d55b0..299bd621f6 100755 --- a/tools/python/xen/xend/server/controller.py +++ b/tools/python/xen/xend/server/controller.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + from twisted.internet import defer import channel @@ -5,6 +7,15 @@ from messages import msgTypeName class CtrlMsgRcvr: """Abstract class for things that deal with a control interface to a domain. + + Instance variables: + + dom : the domain we are a control interface for + majorTypes: list of major message types we are interested in + subTypes : mapping of message subtypes to methods + + channel : channel to the domain + idx : channel index """ @@ -17,6 +28,12 @@ class CtrlMsgRcvr: self.idx = None def requestReceived(self, msg, type, subtype): + """Dispatch a request to handlers. + + msg message + type major message type + subtype minor message type + """ method = self.subTypes.get(subtype) if method: method(msg, 1) @@ -25,6 +42,12 @@ class CtrlMsgRcvr: % (msgTypeName(type, subtype), type, subtype)), self def responseReceived(self, msg, type, subtype): + """Dispatch a response to handlers. + + msg message + type major message type + subtype minor message type + """ method = self.subTypes.get(subtype) if method: method(msg, 0) @@ -33,9 +56,14 @@ class CtrlMsgRcvr: % (msgTypeName(type, subtype), type, subtype)), self def lostChannel(self): + """Called when the channel to the domain is lost. + """ pass def registerChannel(self): + """Register interest in our major message types with the + channel to our domain. + """ #print 'CtrlMsgRcvr>registerChannel>', self self.channel = self.channelFactory.domChannel(self.dom) self.idx = self.channel.getIndex() @@ -43,21 +71,32 @@ class CtrlMsgRcvr: self.channel.registerDevice(self.majorTypes, self) def deregisterChannel(self): + """Deregister interest in our major message types with the + channel to our domain. + """ #print 'CtrlMsgRcvr>deregisterChannel>', self if self.channel: self.channel.deregisterDevice(self) del self.channel def produceRequests(self): + """Produce any queued requests. + + return number produced + """ return 0 def writeRequest(self, msg): + """Write a request to the channel. + """ if self.channel: self.channel.writeRequest(msg) else: print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self def writeResponse(self, msg): + """Write a response to the channel. + """ if self.channel: self.channel.writeResponse(msg) else: @@ -66,6 +105,13 @@ class CtrlMsgRcvr: class ControllerFactory(CtrlMsgRcvr): """Abstract class for factories creating controllers. Maintains a table of instances. + + Instance variables: + + instances : mapping of index to controller instance + dlist : list of deferreds + dom : domain + timeout : deferred timeout """ def __init__(self): @@ -77,34 +123,49 @@ class ControllerFactory(CtrlMsgRcvr): self.timeout = 10 def addInstance(self, instance): + """Add a controller instance (under its index). + """ self.instances[instance.idx] = instance def getInstance(self, idx): + """Get a controller instance from its index. + """ return self.instances.get(idx) def getInstances(self): + """Get a list of all controller instances. + """ return self.instances.values() def getInstanceByDom(self, dom): + """Get the controller instance for the given domain. + """ for inst in self.instances.values(): if inst.dom == dom: return inst return None def delInstance(self, instance): - #print 'ControllerFactory>delInstance>', instance.idx + """Delete an instance from the table. + """ if instance.idx in self.instances: - #print 'ControllerFactory>delInstance> remove', instance.idx del self.instances[instance.idx] def createInstance(self, dom, recreate=0): + """Create an instance. Define in a subclass. + """ raise NotImplementedError() def instanceClosed(self, instance): - #print 'ControllerFactory>instanceClosed>', instance.idx, instance + """Callback called when an instance is closed (usually by the instance). + """ self.delInstance(instance) def addDeferred(self): + """Add a deferred object. + + returns deferred + """ d = defer.Deferred() if self.timeout > 0: # The deferred will error if not called before timeout. @@ -113,11 +174,19 @@ class ControllerFactory(CtrlMsgRcvr): return d def callDeferred(self, *args): + """Call the top deferred object + + args arguments + """ if self.dlist: d = self.dlist.pop(0) d.callback(*args) def errDeferred(self, *args): + """Signal an error to the top deferred object. + + args arguments + """ if self.dlist: d = self.dlist.pop(0) d.errback(*args) @@ -134,15 +203,20 @@ class Controller(CtrlMsgRcvr): self.idx = None def close(self): + """Close the controller. + """ self.deregisterChannel() self.lostChannel() def lostChannel(self): - #print 'Controller>lostChannel>', self, self.factory + """The controller channel has been lost. + """ self.factory.instanceClosed(self) class Dev: - + """Abstract class for a device attached to a device controller. + """ + def __init__(self, controller): self.controller = controller self.props = {} @@ -160,9 +234,6 @@ class Dev: if k in self.props: del self.props[k] - #def __repr__(self): - # return str(self.sxpr()) - def sxpr(self): raise NotImplementedError() diff --git a/tools/python/xen/xend/server/domain.py b/tools/python/xen/xend/server/domain.py index ab22234480..683d352ec0 100644 --- a/tools/python/xen/xend/server/domain.py +++ b/tools/python/xen/xend/server/domain.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import channel import controller from messages import * @@ -7,11 +9,23 @@ class DomainControllerFactory(controller.ControllerFactory): """ def createInstance(self, dom): + """Create a domain controller. + + dom domain + + returns domain controller + """ d = DomainController(self, dom) self.addInstance(d) return d def getInstanceByDom(self, dom): + """Get a domain controller for a domain, creating if necessary. + + dom domain + + returns domain controller + """ for inst in self.instances.values(): if inst.dom == dom: return inst @@ -21,8 +35,11 @@ class DomainControllerFactory(controller.ControllerFactory): class DomainController(controller.Controller): """Generic controller for a domain. + Used for domain shutdown. """ + """Map shutdown reasons to the message type to use. + """ reasons = {'poweroff' : 'shutdown_poweroff_t', 'reboot' : 'shutdown_reboot_t', 'suspend' : 'shutdown_suspend_t' } @@ -34,6 +51,10 @@ class DomainController(controller.Controller): print 'DomainController>', self, self.channel, self.idx def shutdown(self, reason): + """Shutdown a domain. + + reason shutdown reason + """ msgtype = self.reasons.get(reason) if not msgtype: raise ValueError('invalid reason:' + reason) diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py index f3257ca832..bd2c1eed0e 100644 --- a/tools/python/xen/xend/server/messages.py +++ b/tools/python/xen/xend/server/messages.py @@ -148,6 +148,9 @@ netif_formats = { msg_formats.update(netif_formats) #============================================================================ +# Domain shutdown message types. +#============================================================================ + CMSG_SHUTDOWN = 6 CMSG_SHUTDOWN_POWEROFF = 0 @@ -177,6 +180,14 @@ class Msg: pass def packMsg(ty, params): + """Pack a message. + Any 'mac' parameter is passed in as an int[6] array and converted. + + ty message type name + params message parameter dict + + returns xu message + """ if DEBUG: print '>packMsg', ty, params (major, minor) = msg_formats[ty] args = {} @@ -194,6 +205,15 @@ def packMsg(ty, params): return msg def unpackMsg(ty, msg): + """Unpack a message. + Any mac addresses in the message are converted to int[6] array + in the return dict. + + ty message type + msg xu message + + returns parameter dict + """ args = msg.get_payload() mac = [0, 0, 0, 0, 0, 0] macs = [] @@ -212,6 +232,13 @@ def unpackMsg(ty, msg): return args def msgTypeName(ty, subty): + """Convert a message type, subtype pair (ints) to a message type name (string). + + ty integer message type + subty integer message subtype + + returns message type name (or None) + """ for (name, info) in msg_formats.items(): if info[0] == ty and info[1] == subty: return name diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 2b01805be6..5760552e8b 100755 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -1,3 +1,5 @@ +# Copyright (C) 2004 Mike Wray + import random from twisted.internet import defer @@ -30,8 +32,12 @@ class NetifControllerFactory(controller.ControllerFactory): def createInstance(self, dom, recreate=0): """Create or find the network interface controller for a domain. + + dom domain + recreate if true this is a recreate (xend restarted) + + returns netif controller """ - #print 'netif>createInstance> dom=', dom netif = self.getInstanceByDom(dom) if netif is None: netif = NetifController(self, dom) @@ -39,15 +45,31 @@ class NetifControllerFactory(controller.ControllerFactory): return netif def getDomainDevices(self, dom): + """Get the network device controllers for a domain. + + dom domain + + returns netif controller + """ netif = self.getInstanceByDom(dom) return (netif and netif.getDevices()) or [] def getDomainDevice(self, dom, vif): + """Get a virtual network interface device for a domain. + + dom domain + vif virtual interface index + + returns NetDev + """ netif = self.getInstanceByDom(dom) return (netif and netif.getDevice(vif)) or None def setControlDomain(self, dom, recreate=0): """Set the 'back-end' device driver domain. + + dom domain + recreate if true this is a recreate (xend restarted) """ if self.dom == dom: return self.deregisterChannel() @@ -55,13 +77,10 @@ class NetifControllerFactory(controller.ControllerFactory): self.attached = 0 self.dom = dom self.registerChannel() - # - #if xend.netif.be_port.remote_dom != 0: - # xend.netif.recovery = True - # xend.netif.be_port = xend.main.port_from_dom(dom) - # def getControlDomain(self): + """Get the domain id of the back-end control domain. + """ return self.dom def recv_be_create(self, msg, req): @@ -88,23 +107,6 @@ class NetifControllerFactory(controller.ControllerFactory): netif.reattach_devices() self.attached = 1 -## pl = msg.get_payload() -## status = pl['status'] -## if status == NETIF_DRIVER_STATUS_UP: -## if xend.netif.recovery: -## print "New netif backend now UP, notifying guests:" -## for netif_key in interface.list.keys(): -## netif = interface.list[netif_key] -## netif.create() -## print " Notifying %d" % netif.dom -## msg = xu.message( -## CMSG_NETIF_FE, -## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0, -## { 'handle' : 0, 'status' : 1 }) -## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg) -## print "Done notifying guests" -## recovery = False - class NetDev(controller.Dev): """Info record for a network device. """ @@ -130,9 +132,13 @@ class NetDev(controller.Dev): return val def get_vifname(self): + """Get the virtual interface device name. + """ return "vif%d.%d" % (self.controller.dom, self.vif) def get_mac(self): + """Get the MAC address as a string. + """ return ':'.join(map(lambda x: "%x" % x, self.mac)) def vifctl_params(self): @@ -141,23 +147,30 @@ class NetDev(controller.Dev): 'ipaddr': self.ipaddr } def up(self, bridge=None, ipaddr=[]): + """Bring the device up. + + bridge ethernet bridge to connect to + ipaddr list of ipaddrs to filter using iptables + """ self.bridge = bridge self.ipaddr = ipaddr Vifctl.up(self.get_vifname(), **self.vifctl_params()) def down(self): + """Bring the device down. + """ Vifctl.down(self.get_vifname(), **self.vifctl_params()) def destroy(self): + """Destroy the device's resources and disconnect from the back-end + device controller. + """ def cb_destroy(val): self.controller.send_be_destroy(self.vif) - print 'NetDev>destroy>', 'vif=', self.vif - PrettyPrint.prettyprint(self.sxpr()) self.down() d = self.controller.factory.addDeferred() d.addCallback(cb_destroy) self.controller.send_be_disconnect(self.vif) - #self.controller.send_be_destroy(self.vif) class NetifController(controller.Controller): @@ -165,7 +178,6 @@ class NetifController(controller.Controller): """ def __init__(self, factory, dom): - #print 'NetifController> dom=', dom controller.Controller.__init__(self, factory, dom) self.devices = {} @@ -178,21 +190,22 @@ class NetifController(controller.Controller): self.recv_fe_interface_connect, } self.registerChannel() - #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx def sxpr(self): val = ['netif', ['dom', self.dom]] return val def randomMAC(self): - # VIFs get a random MAC address with a "special" vendor id. - # - # NB. The vendor is currently an "obsolete" one that used to belong - # to DEC (AA-00-00). Using it is probably a bit rude :-) - # - # NB2. The first bit of the first random octet is set to zero for - # all dynamic MAC addresses. This may allow us to manually specify - # MAC addresses for some VIFs with no fear of clashes. + """Generate a random MAC address. + + The OUI (Organisation Unique Identifier) used is AA:00:00, which + is a currently unassigned one that used to belong to DEC. + + The remaining 3 fields are random, with the first bit of the first + random field set 0. + + returns array of 6 ints + """ mac = [ 0xaa, 0x00, 0x00, random.randint(0x00, 0x7f), random.randint(0x00, 0xff), @@ -200,29 +213,46 @@ class NetifController(controller.Controller): return mac def lostChannel(self): - print 'NetifController>lostChannel>', 'dom=', self.dom - #self.destroyDevices() + """Method called when the channel has been lost. + """ controller.Controller.lostChannel(self) def getDevices(self): + """Get a list of the devices. + """ return self.devices.values() def getDevice(self, vif): + """Get a device. + + vif device index + + returns device (or None) + """ return self.devices.get(vif) def addDevice(self, vif, vmac): + """Add a network interface. If vmac is None a random MAC is + assigned. If specified, vmac must be a string of the form + XX:XX:XX:XX:XX where X is hex digit. + + vif device index + vmac device MAC + + returns device + """ if vmac is None: mac = self.randomMAC() else: mac = [ int(x, 16) for x in vmac.split(':') ] if len(mac) != 6: raise ValueError("invalid mac") - #print "attach_device>", "vif=", vif, "mac=", mac dev = NetDev(self, vif, mac) self.devices[vif] = dev return dev def destroy(self): - print 'NetifController>destroy>', 'dom=', self.dom + """Destroy the controller and all devices. + """ self.destroyDevices() def destroyDevices(self): @@ -306,7 +336,6 @@ class NetifController(controller.Controller): self.factory.writeRequest(msg) def send_be_destroy(self, vif): - print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif PrettyPrint.prettyprint(self.sxpr()) dev = self.devices[vif] del self.devices[vif] -- 2.30.2